package com.example.lotterysystem.service.mq;

import cn.hutool.core.date.DateUtil;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.utils.JacksonUtil;
import com.example.lotterysystem.common.utils.MailUtil;
import com.example.lotterysystem.controller.param.DrawPrizeParam;
import com.example.lotterysystem.dao.dataobject.ActivityPrizeDO;
import com.example.lotterysystem.dao.dataobject.WinningRecordDO;
import com.example.lotterysystem.dao.mapper.ActivityPrizeMapper;
import com.example.lotterysystem.dao.mapper.WinningRecordMapper;
import com.example.lotterysystem.service.DrawPrizeService;
import com.example.lotterysystem.service.activitystatus.ActivityStatusManager;
import com.example.lotterysystem.service.dto.ConvertActivityStatusDTO;
import com.example.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.example.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.example.lotterysystem.service.enums.ActivityStatusEnum;
import com.example.lotterysystem.service.enums.ActivityUserStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.example.lotterysystem.common.config.DirectRabbitConfig.QUEUE_NAME;

@Component
@RabbitListener(queues = QUEUE_NAME)
public class MqReceiver {

    private final Logger logger = LoggerFactory.getLogger(MqReceiver.class);
    @Autowired
    private DrawPrizeService drawPrizeService;
    @Autowired
    private ActivityStatusManager activityStatusManager;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private MailUtil mailUtil;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;

    @RabbitHandler
    public void process(Map<String,String>  message) {
        //成功接受到消息
        logger.info("Message 成功接受消息: {}" ,
                JacksonUtil.writeValueAsString(message));
        String paramString = message.get("messageData");
        DrawPrizeParam param = JacksonUtil.readValue(paramString, DrawPrizeParam.class);
        //处理抽奖流程
        try {
            //校验抽奖请求是否有效
            drawPrizeService.checkDrawPrizeParam(param);
            //状态扭转处理(最重要) 设计模式
            statusConvert(param);
            //保存中奖者名单
            List<WinningRecordDO> winningRecordDOList =  drawPrizeService.saveWinnerRecords(param);
            //通知中奖者
            syncExecute(winningRecordDOList);


        }catch (ServiceException e){

            logger.error("处理MQ消息异常:{},{}",e.getCode(),e.getMessage(),e);
            //回滚
            rollback(param);
            throw e;

        }catch (Exception e){
            logger.error("处理MQ消息异常:",e);
            rollback(param);
            throw e;
        }



        //如果异常 需要回滚


    }

    /**
     * 处理抽奖异常的回滚行为
     * @param param
     */
    private void rollback(DrawPrizeParam param) {
        //回滚 活动奖品人员
        if(!statusNeedRollback(param)){
            return;
        }
        rollbackStatus(param);



        //回滚 中奖者名单
        if(!winnerNeedRollback(param)){
            return;
        }

        rollbackWinner(param);



    }

    private void rollbackWinner(DrawPrizeParam param) {

        drawPrizeService.deleteRecords(param.getActivityId(), param.getPrizeId());




    }

    private boolean winnerNeedRollback(DrawPrizeParam param) {
        //判断活动中的奖品是否存在中奖者
        int count = winningRecordMapper.countByAPId(param.getActivityId(),param.getPrizeId());




        return count > 0 ;
    }

    /**
     * 恢复相关状态
     * @param param
     */
    private void rollbackStatus(DrawPrizeParam param) {
        ConvertActivityStatusDTO convertActivityStatusDTO = new ConvertActivityStatusDTO();
        convertActivityStatusDTO.setActivityId(param.getActivityId());
        convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.RUNNING);
        convertActivityStatusDTO.setPrizeId(param.getPrizeId());
        convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.INIT);
        convertActivityStatusDTO.setUserIds(
                param.getWinnerList().stream().map(
                        DrawPrizeParam.Winner::getUserId)
                        .collect(Collectors.toList())
                );
        convertActivityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.INIT);


        activityStatusManager.rollbackHandlerEvent(convertActivityStatusDTO);


    }

    private boolean statusNeedRollback(DrawPrizeParam param) {
        //判断活动 奖品 人员 是否已经扭转
        //由于保证了事务的一致性 要么都扭转 要么都不扭转 (不包括活动)
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());
        return activityPrizeDO.getStatus().equalsIgnoreCase(ActivityPrizeStatusEnum.COMPLETED.name());

    }

    //并发
    private void syncExecute(List<WinningRecordDO> winningRecordDOList) {

        //短信通知
        //

        //邮箱通知
        threadPoolTaskExecutor.execute(() -> sendMail(winningRecordDOList));



    }

    /**
     * 发送邮箱
     * @param winningRecordDOList
     */
    private void sendMail(List<WinningRecordDO> winningRecordDOList) {
            if (CollectionUtils.isEmpty(winningRecordDOList)) {
                logger.info("中奖列表为空,不用发邮件");
                return;
            }
            for (WinningRecordDO winningRecordDO : winningRecordDOList) {

                String context = "Hi，" + winningRecordDO.getWinnerName() + "。恭喜你在"
                        + winningRecordDO.getActivityName() + "活动中获得"
                        + ActivityPrizeTiersEnum.forName(winningRecordDO.getPrizeTier()).getMessage()
                        + "：" + winningRecordDO.getPrizeName() + "。获奖时间为"
                        + DateUtil.formatTime(winningRecordDO.getWinningTime()) + "，请尽快领 取您的奖励！";

                mailUtil.sendSampleMail(winningRecordDO.getWinnerEmail(),"中奖通知",context);

            }

    }

    /**
     * 状态扭转
     * @param param
     */
    private void statusConvert(DrawPrizeParam param){
        ConvertActivityStatusDTO convertActivityStatusDTO = new ConvertActivityStatusDTO();
        convertActivityStatusDTO.setActivityId(param.getActivityId());
        convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.COMPLETED);
        convertActivityStatusDTO.setPrizeId(param.getPrizeId());
        convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.COMPLETED);
        convertActivityStatusDTO.setUserIds(
                param.getWinnerList().stream()
                        .map(DrawPrizeParam.Winner::getUserId)
                        .collect(Collectors.toList())
        );
        convertActivityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.COMPLETED);

        activityStatusManager.handlerEvent(convertActivityStatusDTO);
    }

//    private void statusConvert(DrawPrizeParam param) {
//
//        //活动 RUNNING->COMPLETED 全部奖品抽完
//        //奖品:INIT -> COMPLETED
//        //人员:列表INIT -> COMPLETED
//
//
//        //查询活动关联的奖品信息
//        //判断当前状态是否是COMPLETED,如果是就不扭转
//
//        //1.扭转奖品状态
//
//
//
//
//        //2.扭转人员状态
//
//
//        //3.扭转活动状态 全部奖品抽完才改变
//
//
//
//
//    }


}
